// Copyright © 2019 The Things Network Foundation, The Things Industries B.V.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package devicetemplates_test

import (
	"bytes"
	"testing"

	"github.com/smarty/assertions"
	. "go.thethings.network/lorawan-stack/v3/pkg/devicetemplates"
	"go.thethings.network/lorawan-stack/v3/pkg/log"
	"go.thethings.network/lorawan-stack/v3/pkg/provisioning"
	"go.thethings.network/lorawan-stack/v3/pkg/ttnpb"
	"go.thethings.network/lorawan-stack/v3/pkg/types"
	"go.thethings.network/lorawan-stack/v3/pkg/util/test"
	"go.thethings.network/lorawan-stack/v3/pkg/util/test/assertions/should"
)

func TestMicrochipATECC608AMAHTNT(t *testing.T) {
	a := assertions.New(t)
	ctx := log.NewContext(test.Context(), test.GetLogger(t))

	converter := GetConverter("microchip-atecc608a-mahtn-t")
	if !a.So(converter, should.NotBeNil) {
		t.FailNow()
	}

	format := converter.Format()
	a.So(format.Name, should.Equal, "Microchip ATECC608A-MAHTN-T Manifest File")

	data := []byte(`[{
		"payload": "eyJ2ZXJzaW9uIjogMSwgIm1vZGVsIjogIkFURUNDNjA4QSIsICJwYXJ0TnVtYmVyIjogIkFURUNDNjA4QS1NQUhUMiIsICJtYW51ZmFjdHVyZXIiOiB7Im9yZ2FuaXphdGlvbk5hbWUiOiAiTWljcm9jaGlwIFRlY2hub2xvZ3kgSW5jIiwgIm9yZ2FuaXphdGlvbmFsVW5pdE5hbWUiOiAiU2VjdXJlIFByb2R1Y3RzIEdyb3VwIn0sICJwcm92aXNpb25lciI6IHsib3JnYW5pemF0aW9uTmFtZSI6ICJNaWNyb2NoaXAgVGVjaG5vbG9neSBJbmMiLCAib3JnYW5pemF0aW9uYWxVbml0TmFtZSI6ICJTZWN1cmUgUHJvZHVjdHMgR3JvdXAifSwgImRpc3RyaWJ1dG9yIjogeyJvcmdhbml6YXRpb25OYW1lIjogIk1pY3JvY2hpcCBUZWNobm9sb2d5IEluYyIsICJvcmdhbml6YXRpb25hbFVuaXROYW1lIjogIk1pY3JvY2hpcCBEaXJlY3QifSwgImdyb3VwSWQiOiAiSkVFTERBSldTUDJKQUdBMyIsICJwcm92aXNpb25pbmdUaW1lc3RhbXAiOiAiMjAxOS0wMS0xNFQxODozMjoyMS44NjdaIiwgInVuaXF1ZUlkIjogIjAxMjM3YTAwNWIwOGJjYzUyNyIsICJwdWJsaWNLZXlTZXQiOiB7ImtleXMiOiBbeyJraWQiOiAiMSIsICJrdHkiOiAiRUMiLCAiY3J2IjogIlAtMjU2IiwgIngiOiAienNTNjNUMnRUdXJTT2E1dmRVamlkU0U2NVJGc3VYOERjNDYwQkpmVE1nND0iLCAieSI6ICI2MmZIa3E1MzVWWE5Ubnc0ZXUxeDRhYl9fM3daRHkyVUh0Q3I3WkpzNmowPSIsICJ4NWMiOiBbIk1JSUI5VENDQVp1Z0F3SUJBZ0lRZE5OdXJPVi9UNTEycnpIb2t2ZlEyekFLQmdncWhrak9QUVFEQWpCUE1TRXdId1lEVlFRS0RCaE5hV055YjJOb2FYQWdWR1ZqYUc1dmJHOW5lU0JKYm1NeEtqQW9CZ05WQkFNTUlVTnllWEIwYnlCQmRYUm9aVzUwYVdOaGRHbHZiaUJUYVdkdVpYSWdSall3TVRBZ0Z3MHhPVEF4TVRReE9EQXdNREJhR0E4eU1EUTNNREV4TkRFNE1EQXdNRm93UmpFaE1COEdBMVVFQ2d3WVRXbGpjbTlqYUdsd0lGUmxZMmh1YjJ4dloza2dTVzVqTVNFd0h3WURWUVFEREJnd01USXpOMEV3TURWQ01EaENRME0xTWpjZ1FWUkZRME13V1RBVEJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVRPeExyZFBhMU82dEk1cm05MVNPSjFJVHJsRVd5NWZ3TnpqclFFbDlNeUR1dG54NUt1ZCtWVnpVNThPSHJ0Y2VHbS8vOThHUTh0bEI3UXErMlNiT285bzJBd1hqQU1CZ05WSFJNQkFmOEVBakFBTUE0R0ExVWREd0VCL3dRRUF3SURpREFkQmdOVkhRNEVGZ1FVNzBNUy9CdjVMK2gvUWdKbkp6a3A4b0phVy84d0h3WURWUjBqQkJnd0ZvQVU4VE1wdElQSDdkWnVRZGtRbHl3cytCbXR5dWd3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnTFpML2lJSElTaE1mMXRTSkFkRTRLcXI4Tlp0QmllSVhleG1QS2F1cEtzb0NJUUNYZWtQUTdCQm1BOHpiR0NjVnhDRTM5ZEdnQTNsSGhFMnRDWlp1Y04zS0tBPT0iLCAiTUlJQ0JEQ0NBYXFnQXdJQkFnSVFhc2ExbEttdzR1WG5haEdQNXdCZEFEQUtCZ2dxaGtqT1BRUURBakJQTVNFd0h3WURWUVFLREJoTmFXTnliMk5vYVhBZ1ZHVmphRzV2Ykc5bmVTQkpibU14S2pBb0JnTlZCQU1NSVVOeWVYQjBieUJCZFhSb1pXNTBhV05oZEdsdmJpQlNiMjkwSUVOQklEQXdNakFnRncweE9ERXlNVFF4T1RBd01EQmFHQTh5TURRNU1USXhOREU1TURBd01Gb3dUekVoTUI4R0ExVUVDZ3dZVFdsamNtOWphR2x3SUZSbFkyaHViMnh2WjNrZ1NXNWpNU293S0FZRFZRUUREQ0ZEY25sd2RHOGdRWFYwYUdWdWRHbGpZWFJwYjI0Z1UybG5ibVZ5SUVZMk1ERXdXVEFUQmdjcWhrak9QUUlCQmdncWhrak9QUU1CQndOQ0FBVFc5QzVRTU5PT2VKNUZIMkU1THhqdHpNVjlQbXNLL1R6R1hwQmswVm9NYzhsSVZmWkJTWUhxUkh6QXpoRWF5RTRBem1LZDhnbGJGbFdYYTNXRWhON0NvMll3WkRBT0JnTlZIUThCQWY4RUJBTUNBWVl3RWdZRFZSMFRBUUgvQkFnd0JnRUIvd0lCQURBZEJnTlZIUTRFRmdRVThUTXB0SVBIN2RadVFka1FseXdzK0JtdHl1Z3dId1lEVlIwakJCZ3dGb0FVZXUxOWJjYTNlSjJ5T0FHbDZFcU1zS1FPS293d0NnWUlLb1pJemowRUF3SURTQUF3UlFJaEFPYnk0N2pjejJHT2Q3M0NPQzVjQXJrNnlCNDRyd2hJeWFQbHJEMERTU2FVQWlCakU1RGkzMXgrc0RxY3FvR09jaFNhMmJlcnF4Q0taU1dyRTExUWd4ZjBJdz09Il19XX19",
		"protected": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IkIwdWFETExpeUtlLVNvclA3MUYzQk5vVnJmWSIsIng1dCNTMjU2IjoiVmFURzFGWjV4Z25CUXV4U2FkV09iWFRIMmhQUkxqSFQtNER6VmFKTTNvbyJ9",
		"signature": "rOrjAQyI1FQO-RmNjS0ggA7t4U7l9epwCbTQYnyb92j2EOqZ3vNhF5RAMldvG68v6w25mKrGaPG8wdn--TSy4w"
	}]`)

	calls := 0
	f := func(entry *ttnpb.EndDeviceTemplate) error {
		calls++
		a.So(
			entry.EndDevice.Ids.JoinEui,
			should.Resemble,
			types.EUI64{0x70, 0xB3, 0xD5, 0x7E, 0xD0, 0x00, 0x00, 0x00}.Bytes(),
		)
		a.So(entry.EndDevice.ProvisionerId, should.Equal, provisioning.Microchip)
		a.So(entry.EndDevice.RootKeys.GetRootKeyId(), should.Equal, "01237a005b08bcc527")
		a.So(entry.EndDevice.SupportsJoin, should.BeTrue)
		a.So(entry.MappingKey, should.Equal, "01237a005b08bcc527")
		return nil
	}
	err := converter.Convert(ctx, bytes.NewReader(data), f)
	a.So(err, should.BeNil)
	a.So(calls, should.Equal, 1)
}

func TestMicrochipATECC608ATNGLORA(t *testing.T) {
	a := assertions.New(t)
	ctx := log.NewContext(test.Context(), test.GetLogger(t))

	converter := GetConverter("microchip-atecc608a-tnglora")
	if !a.So(converter, should.NotBeNil) {
		t.FailNow()
	}

	format := converter.Format()
	a.So(format.Name, should.Equal, "Microchip ATECC608A-TNGLORA Manifest File")

	// Garbage in, test error.
	{
		data := []byte(`garbage`)

		err := converter.Convert(ctx, bytes.NewReader(data), func(*ttnpb.EndDeviceTemplate) error {
			t.FailNow()
			return nil
		})
		a.So(err, should.NotBeNil)
	}

	// Test bad signature.
	{
		data := []byte(`[{
			"payload": "eyJ2ZXJzaW9uIjoxLCJtb2RlbCI6IkFURUNDNjA4QSIsInBhcnROdW1iZXIiOiJBVEVDQzYwOEEtTUFIVDMiLCJtYW51ZmFjdHVyZXIiOnsib3JnYW5pemF0aW9uTmFtZSI6Ik1pY3JvY2hpcCBUZWNobm9sb2d5IEluYyIsIm9yZ2FuaXphdGlvbmFsVW5pdE5hbWUiOiJTZWN1cmUgUHJvZHVjdHMgR3JvdXAifSwicHJvdmlzaW9uZXIiOnsib3JnYW5pemF0aW9uTmFtZSI6Ik1pY3JvY2hpcCBUZWNobm9sb2d5IEluYyIsIm9yZ2FuaXphdGlvbmFsVW5pdE5hbWUiOiJTZWN1cmUgUHJvZHVjdHMgR3JvdXAifSwiZGlzdHJpYnV0b3IiOnsib3JnYW5pemF0aW9uTmFtZSI6Ik1pY3JvY2hpcCBUZWNobm9sb2d5IEluYyIsIm9yZ2FuaXphdGlvbmFsVW5pdE5hbWUiOiJNaWNyb2NoaXAgRGlyZWN0In0sImdyb3VwSWQiOiJVbmtub3duIiwicHJvdmlzaW9uaW5nVGltZXN0YW1wIjoiMjAxOS0wOS0yMFQxNjoxODo0NS4zOTBaIiwidW5pcXVlSWQiOiIwMTIzOGViZTIwMDgwYmQ1MjciLCJwdWJsaWNLZXlTZXQiOnsia2V5cyI6W3sia2lkIjoiMSIsImt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoiQ0xqaDVQd05FOUl1c0NOLXlRWm4tRldBUlBiZGV6LUNEVy1DVEpELVNIYyIsInkiOiItaEZ6dl9ZQ0dsWG1hNUJfc3pudENzWVB0NTE3eHhNZTJwZU9PSDc5bk5vIiwieDVjIjpbIk1JSUNCakNDQWF5Z0F3SUJBZ0lRVVVPdDFqT3hJckVwK25QOW83VUNpekFLQmdncWhrak9QUVFEQWpCUE1TRXdId1lEVlFRS0RCaE5hV055YjJOb2FYQWdWR1ZqYUc1dmJHOW5lU0JKYm1NeEtqQW9CZ05WQkFNTUlVTnllWEIwYnlCQmRYUm9aVzUwYVdOaGRHbHZiaUJUYVdkdVpYSWdSall3TVRBZ0Z3MHhPVEE1TWpBeE5qQXdNREJhR0E4eU1EUTNNRGt5TURFMk1EQXdNRm93VnpFaE1COEdBMVVFQ2d3WVRXbGpjbTlqYUdsd0lGUmxZMmh1YjJ4dloza2dTVzVqTVRJd01BWURWUVFERENrd01USXpPRVZDUlRJd01EZ3dRa1ExTWpjZ01EQXdORUV6TVRBd01ERkdSamxFUVNCQlZFVkRRekJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEEwSUFCQWk0NGVUOERSUFNMckFqZnNrR1ovaFZnRVQyM1hzL2dnMXZna3lRL2toMytoRnp2L1lDR2xYbWE1Qi9zem50Q3NZUHQ1MTd4eE1lMnBlT09INzluTnFqWURCZU1Bd0dBMVVkRXdFQi93UUNNQUF3RGdZRFZSMFBBUUgvQkFRREFnT0lNQjBHQTFVZERnUVdCQlJpVUVNMnEwM3NLZTUvdnJxNXQyUTF5RW0xZnpBZkJnTlZIU01FR0RBV2dCVHhNeW0wZzhmdDFtNUIyUkNYTEN6NEdhM0s2REFLQmdncWhrak9QUVFEQWdOSUFEQkZBaUVBL0MxVnhFcGdEMGtxSFFCV1p4NUowNlVzeElHMDMySjZDaHlWU3VnbWdEUUNJRjJXR2tzSjhTenQ3ZmJzUEtlRWFFUnNxQ1hubDYwaFp1b1hkVkZkVDJyMiIsIk1JSUNCRENDQWFxZ0F3SUJBZ0lRYXNhMWxLbXc0dVhuYWhHUDV3QmRBREFLQmdncWhrak9QUVFEQWpCUE1TRXdId1lEVlFRS0RCaE5hV055YjJOb2FYQWdWR1ZqYUc1dmJHOW5lU0JKYm1NeEtqQW9CZ05WQkFNTUlVTnllWEIwYnlCQmRYUm9aVzUwYVdOaGRHbHZiaUJTYjI5MElFTkJJREF3TWpBZ0Z3MHhPREV5TVRReE9UQXdNREJhR0E4eU1EUTVNVEl4TkRFNU1EQXdNRm93VHpFaE1COEdBMVVFQ2d3WVRXbGpjbTlqYUdsd0lGUmxZMmh1YjJ4dloza2dTVzVqTVNvd0tBWURWUVFERENGRGNubHdkRzhnUVhWMGFHVnVkR2xqWVhScGIyNGdVMmxuYm1WeUlFWTJNREV3V1RBVEJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVRXOUM1UU1OT09lSjVGSDJFNUx4anR6TVY5UG1zSy9UekdYcEJrMFZvTWM4bElWZlpCU1lIcVJIekF6aEVheUU0QXptS2Q4Z2xiRmxXWGEzV0VoTjdDbzJZd1pEQU9CZ05WSFE4QkFmOEVCQU1DQVlZd0VnWURWUjBUQVFIL0JBZ3dCZ0VCL3dJQkFEQWRCZ05WSFE0RUZnUVU4VE1wdElQSDdkWnVRZGtRbHl3cytCbXR5dWd3SHdZRFZSMGpCQmd3Rm9BVWV1MTliY2EzZUoyeU9BR2w2RXFNc0tRT0tvd3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWhBT2J5NDdqY3oyR09kNzNDT0M1Y0FyazZ5QjQ0cndoSXlhUGxyRDBEU1NhVUFpQmpFNURpMzF4K3NEcWNxb0dPY2hTYTJiZXJxeENLWlNXckUxMVFneGYwSXc9PSJdfV19LCJtb2RlbEluZm8iOnsicHVibGljRGF0YSI6W3siem9uZSI6ImRhdGEiLCJzbG90Ijo5LCJvZmZzZXQiOjAsImRhdGEiOiJjTFBWZnRBQUFBQUFBQUFBQUFBQUFKa0ltUW1aQ3BrTG1ReVpEWmtPbVEtWkVKa1JtUktaRTVrVW1SV1pGcGtYbVJpWkdaa2FtUnVaSEprZG1SNlpINWtnbVNHWklwa2oifV19fQ",
			"protected": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IjhWZUtHZHlVMmQ4d2V2Nl9Wek5KT0JPdi1jQSIsIng1dCNTMjU2IjoiVTlUS213NGYzaUc1Nk9HUjhZVl9OY3hsazBEbEcwRnlMOWFEbHdmYnYxQSJ9",
			"header": {
				"uniqueId": "01238ebe20080bd527"
			},
			"signature": "ZFhl0AAAAAAAIOVqvmDtmYdNytq6WBK5zH1GcN0nu7VkkM1k4hbowUEfyTDZKlam3LvdPLcKM13Z6oEifQ"
		}]`)

		err := converter.Convert(ctx, bytes.NewReader(data), func(*ttnpb.EndDeviceTemplate) error {
			t.FailNow()
			return nil
		})
		a.So(err, should.NotBeNil)
	}

	// Test valid manifest B-generation entry.
	{
		data := []byte(`[{
			"payload": "eyJ2ZXJzaW9uIjoxLCJtb2RlbCI6IkFURUNDNjA4QSIsInBhcnROdW1iZXIiOiJBVEVDQzYwOEEtTUFIVDMiLCJtYW51ZmFjdHVyZXIiOnsib3JnYW5pemF0aW9uTmFtZSI6Ik1pY3JvY2hpcCBUZWNobm9sb2d5IEluYyIsIm9yZ2FuaXphdGlvbmFsVW5pdE5hbWUiOiJTZWN1cmUgUHJvZHVjdHMgR3JvdXAifSwicHJvdmlzaW9uZXIiOnsib3JnYW5pemF0aW9uTmFtZSI6Ik1pY3JvY2hpcCBUZWNobm9sb2d5IEluYyIsIm9yZ2FuaXphdGlvbmFsVW5pdE5hbWUiOiJTZWN1cmUgUHJvZHVjdHMgR3JvdXAifSwiZGlzdHJpYnV0b3IiOnsib3JnYW5pemF0aW9uTmFtZSI6Ik1pY3JvY2hpcCBUZWNobm9sb2d5IEluYyIsIm9yZ2FuaXphdGlvbmFsVW5pdE5hbWUiOiJNaWNyb2NoaXAgRGlyZWN0In0sImdyb3VwSWQiOiJVbmtub3duIiwicHJvdmlzaW9uaW5nVGltZXN0YW1wIjoiMjAxOS0wOS0yMFQxNjoxODo0NS4zOTBaIiwidW5pcXVlSWQiOiIwMTIzOGViZTIwMDgwYmQ1MjciLCJwdWJsaWNLZXlTZXQiOnsia2V5cyI6W3sia2lkIjoiMSIsImt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoiQ0xqaDVQd05FOUl1c0NOLXlRWm4tRldBUlBiZGV6LUNEVy1DVEpELVNIYyIsInkiOiItaEZ6dl9ZQ0dsWG1hNUJfc3pudENzWVB0NTE3eHhNZTJwZU9PSDc5bk5vIiwieDVjIjpbIk1JSUNCakNDQWF5Z0F3SUJBZ0lRVVVPdDFqT3hJckVwK25QOW83VUNpekFLQmdncWhrak9QUVFEQWpCUE1TRXdId1lEVlFRS0RCaE5hV055YjJOb2FYQWdWR1ZqYUc1dmJHOW5lU0JKYm1NeEtqQW9CZ05WQkFNTUlVTnllWEIwYnlCQmRYUm9aVzUwYVdOaGRHbHZiaUJUYVdkdVpYSWdSall3TVRBZ0Z3MHhPVEE1TWpBeE5qQXdNREJhR0E4eU1EUTNNRGt5TURFMk1EQXdNRm93VnpFaE1COEdBMVVFQ2d3WVRXbGpjbTlqYUdsd0lGUmxZMmh1YjJ4dloza2dTVzVqTVRJd01BWURWUVFERENrd01USXpPRVZDUlRJd01EZ3dRa1ExTWpjZ01EQXdORUV6TVRBd01ERkdSamxFUVNCQlZFVkRRekJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEEwSUFCQWk0NGVUOERSUFNMckFqZnNrR1ovaFZnRVQyM1hzL2dnMXZna3lRL2toMytoRnp2L1lDR2xYbWE1Qi9zem50Q3NZUHQ1MTd4eE1lMnBlT09INzluTnFqWURCZU1Bd0dBMVVkRXdFQi93UUNNQUF3RGdZRFZSMFBBUUgvQkFRREFnT0lNQjBHQTFVZERnUVdCQlJpVUVNMnEwM3NLZTUvdnJxNXQyUTF5RW0xZnpBZkJnTlZIU01FR0RBV2dCVHhNeW0wZzhmdDFtNUIyUkNYTEN6NEdhM0s2REFLQmdncWhrak9QUVFEQWdOSUFEQkZBaUVBL0MxVnhFcGdEMGtxSFFCV1p4NUowNlVzeElHMDMySjZDaHlWU3VnbWdEUUNJRjJXR2tzSjhTenQ3ZmJzUEtlRWFFUnNxQ1hubDYwaFp1b1hkVkZkVDJyMiIsIk1JSUNCRENDQWFxZ0F3SUJBZ0lRYXNhMWxLbXc0dVhuYWhHUDV3QmRBREFLQmdncWhrak9QUVFEQWpCUE1TRXdId1lEVlFRS0RCaE5hV055YjJOb2FYQWdWR1ZqYUc1dmJHOW5lU0JKYm1NeEtqQW9CZ05WQkFNTUlVTnllWEIwYnlCQmRYUm9aVzUwYVdOaGRHbHZiaUJTYjI5MElFTkJJREF3TWpBZ0Z3MHhPREV5TVRReE9UQXdNREJhR0E4eU1EUTVNVEl4TkRFNU1EQXdNRm93VHpFaE1COEdBMVVFQ2d3WVRXbGpjbTlqYUdsd0lGUmxZMmh1YjJ4dloza2dTVzVqTVNvd0tBWURWUVFERENGRGNubHdkRzhnUVhWMGFHVnVkR2xqWVhScGIyNGdVMmxuYm1WeUlFWTJNREV3V1RBVEJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVRXOUM1UU1OT09lSjVGSDJFNUx4anR6TVY5UG1zSy9UekdYcEJrMFZvTWM4bElWZlpCU1lIcVJIekF6aEVheUU0QXptS2Q4Z2xiRmxXWGEzV0VoTjdDbzJZd1pEQU9CZ05WSFE4QkFmOEVCQU1DQVlZd0VnWURWUjBUQVFIL0JBZ3dCZ0VCL3dJQkFEQWRCZ05WSFE0RUZnUVU4VE1wdElQSDdkWnVRZGtRbHl3cytCbXR5dWd3SHdZRFZSMGpCQmd3Rm9BVWV1MTliY2EzZUoyeU9BR2w2RXFNc0tRT0tvd3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWhBT2J5NDdqY3oyR09kNzNDT0M1Y0FyazZ5QjQ0cndoSXlhUGxyRDBEU1NhVUFpQmpFNURpMzF4K3NEcWNxb0dPY2hTYTJiZXJxeENLWlNXckUxMVFneGYwSXc9PSJdfV19LCJtb2RlbEluZm8iOnsicHVibGljRGF0YSI6W3siem9uZSI6ImRhdGEiLCJzbG90Ijo5LCJvZmZzZXQiOjAsImRhdGEiOiJjTFBWZnRBQUFBQUFBQUFBQUFBQUFKa0ltUW1aQ3BrTG1ReVpEWmtPbVEtWkVKa1JtUktaRTVrVW1SV1pGcGtYbVJpWkdaa2FtUnVaSEprZG1SNlpINWtnbVNHWklwa2oifV19fQ",
			"protected": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IjhWZUtHZHlVMmQ4d2V2Nl9Wek5KT0JPdi1jQSIsIng1dCNTMjU2IjoiVTlUS213NGYzaUc1Nk9HUjhZVl9OY3hsazBEbEcwRnlMOWFEbHdmYnYxQSJ9",
			"header": {
				"uniqueId": "01238ebe20080bd527"
			},
			"signature": "ZFhl07osmnG8pB0AIOVqvmDtmYdNytq6WBK5zH1GcN0nu7VkkM1k4hbowUEfyTDZKlam3LvdPLcKM13Z6oEifQ"
		}]`)

		calls := 0
		f := func(entry *ttnpb.EndDeviceTemplate) error {
			calls++
			a.So(entry.EndDevice.Ids.DeviceId, should.Equal, "eui-0004a310001ff9da")
			a.So(
				entry.EndDevice.Ids.JoinEui,
				should.Resemble,
				types.EUI64{0x70, 0xB3, 0xD5, 0x7E, 0xD0, 0x00, 0x00, 0x00}.Bytes(),
			)
			a.So(
				entry.EndDevice.Ids.DevEui,
				should.Resemble,
				types.EUI64{0x00, 0x04, 0xA3, 0x10, 0x00, 0x1F, 0xF9, 0xDA}.Bytes(),
			)
			a.So(entry.EndDevice.ProvisionerId, should.Equal, provisioning.Microchip)
			a.So(entry.EndDevice.RootKeys.GetRootKeyId(), should.Equal, "01238ebe20080bd527")
			a.So(entry.EndDevice.SupportsJoin, should.BeTrue)
			a.So(entry.MappingKey, should.Equal, "01238ebe20080bd527")
			return nil
		}
		err := converter.Convert(ctx, bytes.NewReader(data), f)
		a.So(err, should.BeNil)
		a.So(calls, should.Equal, 1)
	}

	// Test valid manifest C-generation entry.
	{
		data := []byte(`[{
			"payload": "eyJ2ZXJzaW9uIjoxLCJtb2RlbCI6IkFURUNDNjA4QSIsInBhcnROdW1iZXIiOiJBVEVDQzYwOEEtTUFIVDMiLCJtYW51ZmFjdHVyZXIiOnsib3JnYW5pemF0aW9uTmFtZSI6Ik1pY3JvY2hpcCBUZWNobm9sb2d5IEluYyIsIm9yZ2FuaXphdGlvbmFsVW5pdE5hbWUiOiJTZWN1cmUgUHJvZHVjdHMgR3JvdXAifSwicHJvdmlzaW9uZXIiOnsib3JnYW5pemF0aW9uTmFtZSI6Ik1pY3JvY2hpcCBUZWNobm9sb2d5IEluYyIsIm9yZ2FuaXphdGlvbmFsVW5pdE5hbWUiOiJTZWN1cmUgUHJvZHVjdHMgR3JvdXAifSwiZGlzdHJpYnV0b3IiOnsib3JnYW5pemF0aW9uTmFtZSI6Ik1pY3JvY2hpcCBUZWNobm9sb2d5IEluYyIsIm9yZ2FuaXphdGlvbmFsVW5pdE5hbWUiOiJNaWNyb2NoaXAgRGlyZWN0In0sImdyb3VwSWQiOiI2NzlNR0ZDOEhaQlNEN0JHIiwicHJvdmlzaW9uaW5nVGltZXN0YW1wIjoiMjAxOS0xMi0xMlQwNTo1MzoyNy43MTdaIiwidW5pcXVlSWQiOiIwMTIzMTE0ZTE3MWI5OGI0MjciLCJwdWJsaWNLZXlTZXQiOnsia2V5cyI6W3sia2lkIjoiMSIsImt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoiSnFEeHA5R0hxVmVaWXdwQ3owcHZWUVZXNkZyX0hQV0s4SWtpbFhFS0lVTSIsInkiOiJIWHB0RmVxQi1KYXVEUEJZZGJaRjE3ektoVEI3SXZKa0lqN1NGNllfd240IiwieDVjIjpbIk1JSUNJakNDQWNtZ0F3SUJBZ0lRWDI2NkprYTVtc1JHKzhTb0tMN21aakFLQmdncWhrak9QUVFEQWpCUE1TRXdId1lEVlFRS0RCaE5hV055YjJOb2FYQWdWR1ZqYUc1dmJHOW5lU0JKYm1NeEtqQW9CZ05WQkFNTUlVTnllWEIwYnlCQmRYUm9aVzUwYVdOaGRHbHZiaUJUYVdkdVpYSWdNamN3TVRBZ0Z3MHhPVEV5TVRJd05UQXdNREJhR0E4eU1EUTNNVEl4TWpBMU1EQXdNRm93UWpFaE1COEdBMVVFQ2d3WVRXbGpjbTlqYUdsd0lGUmxZMmh1YjJ4dloza2dTVzVqTVIwd0d3WURWUVFEREJSemJqQXhNak14TVRSRk1UY3hRams0UWpReU56QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJDYWc4YWZSaDZsWG1XTUtRczlLYjFVRlZ1aGEveHoxaXZDSklwVnhDaUZESFhwdEZlcUIrSmF1RFBCWWRiWkYxN3pLaFRCN0l2SmtJajdTRjZZL3duNmpnWkV3Z1k0d0xnWURWUjBSQkNjd0phUWpNQ0V4SHpBZEJnTlZCQVVURm1WMWFUWTBYekF3TURSQk16RXdNREF4UVVFNU1FRXdEQVlEVlIwVEFRSC9CQUl3QURBT0JnTlZIUThCQWY4RUJBTUNBNGd3SFFZRFZSME9CQllFRkRrdzBEckRDaFZvb3MrQm5NT3NkSDJlcUVtWU1COEdBMVVkSXdRWU1CYUFGSjB2SGNoUFJnVnBXekZ4QytLY2M5NGpRakJiTUFvR0NDcUdTTTQ5QkFNQ0EwY0FNRVFDSUN5ZDFOYXRsTzlveWRVK0UrUEFDQWxobUVxbm11RmI3RlQ5bk1ObWF0b3RBaUFXbC90NnRwUEtuTldTWWFQRHZlZzRod1UwY0p4bDlXS29Bd2g0amw0Qk1RPT0iLCJNSUlDQkRDQ0FhcWdBd0lCQWdJUWY4WWFEQ2ljNHdFY2grdDVFWEU4NXpBS0JnZ3Foa2pPUFFRREFqQlBNU0V3SHdZRFZRUUtEQmhOYVdOeWIyTm9hWEFnVkdWamFHNXZiRzluZVNCSmJtTXhLakFvQmdOVkJBTU1JVU55ZVhCMGJ5QkJkWFJvWlc1MGFXTmhkR2x2YmlCU2IyOTBJRU5CSURBd01qQWdGdzB4T0RFeU1UUXlNREF3TURCYUdBOHlNRFE1TVRJeE5ESXdNREF3TUZvd1R6RWhNQjhHQTFVRUNnd1lUV2xqY205amFHbHdJRlJsWTJodWIyeHZaM2tnU1c1ak1Tb3dLQVlEVlFRRERDRkRjbmx3ZEc4Z1FYVjBhR1Z1ZEdsallYUnBiMjRnVTJsbmJtVnlJREkzTURFd1dUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFTUVJEVlNEelA3MGlyVVJvanRDWDBGbmUvODVBS3grRGYzdVVxeXRxaXZ2VWhOSkE3M2s2Ym5tZWYyUnBRN2VraHFUUERGWjcrNkJrRDFIL3loUDA0S28yWXdaREFPQmdOVkhROEJBZjhFQkFNQ0FZWXdFZ1lEVlIwVEFRSC9CQWd3QmdFQi93SUJBREFkQmdOVkhRNEVGZ1FVblM4ZHlFOUdCV2xiTVhFTDRweHozaU5DTUZzd0h3WURWUjBqQkJnd0ZvQVVldTE5YmNhM2VKMnlPQUdsNkVxTXNLUU9Lb3d3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnZjR4OWhNV2llcVc3N0x6dE5iMytMTnVNQ0VBaTYxNnRyaVpvZ3d2ZnlGUUNJUUNFMXlnWTlIdmU1VmdDWWVjbjFEeHNla3V6eC9JRG1PdFVlVmM0eUZydzlRPT0iXX1dfSwibW9kZWxJbmZvIjp7InB1YmxpY0RhdGEiOlt7InpvbmUiOiJkYXRhIiwic2xvdCI6OSwib2Zmc2V0IjowLCJkYXRhIjoiY0xQVmZ0QUFBQUFBQUFBQUFBQUFBSmtJbVFtWkNwa0xtUXlaRFprT21RLVpFSmtSbVJLWkU1a1VtUldaRnBrWG1SaVpHWmthbVJ1WkhKa2RtUjZaSDVrZ21TR1pJcGtqIn1dfX0",
			"protected": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IjhWZUtHZHlVMmQ4d2V2Nl9Wek5KT0JPdi1jQSIsIng1dCNTMjU2IjoiVTlUS213NGYzaUc1Nk9HUjhZVl9OY3hsazBEbEcwRnlMOWFEbHdmYnYxQSJ9",
			"header": {
				"uniqueId": "0123114e171b98b427"
			},
			"signature": "qWE59pmZpI7jx0Unr8zFjF-H-FRPBeDaOLM_wfeZwMb_RizRnLLh0tB1Taep6hcIVauZbOK2iI59GDMxb0meEw"
		}]`)

		calls := 0
		f := func(entry *ttnpb.EndDeviceTemplate) error {
			calls++
			a.So(entry.EndDevice.Ids.DeviceId, should.Equal, "eui-0004a310001aa90a")
			a.So(
				entry.EndDevice.Ids.JoinEui,
				should.Resemble,
				types.EUI64{0x70, 0xB3, 0xD5, 0x7E, 0xD0, 0x00, 0x00, 0x00}.Bytes(),
			)
			a.So(entry.EndDevice.Ids.DevEui,
				should.Resemble,
				types.EUI64{0x00, 0x04, 0xA3, 0x10, 0x00, 0x1A, 0xA9, 0x0A}.Bytes(),
			)
			a.So(entry.EndDevice.ProvisionerId, should.Equal, provisioning.Microchip)
			a.So(entry.EndDevice.RootKeys.GetRootKeyId(), should.Equal, "0123114e171b98b427")
			a.So(entry.EndDevice.SupportsJoin, should.BeTrue)
			a.So(entry.MappingKey, should.Equal, "0123114e171b98b427")
			return nil
		}
		err := converter.Convert(ctx, bytes.NewReader(data), f)
		a.So(err, should.BeNil)
		a.So(calls, should.Equal, 1)
	}
}
